home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / pstats.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2005-10-18  |  21KB  |  704 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.4)
  3.  
  4. '''Class for printing reports on profiled python code.'''
  5. import os
  6. import time
  7. import marshal
  8. import re
  9. __all__ = [
  10.     'Stats']
  11.  
  12. class Stats:
  13.     '''This class is used for creating reports from data generated by the
  14.     Profile class.  It is a "friend" of that class, and imports data either
  15.     by direct access to members of Profile class, or by reading in a dictionary
  16.     that was emitted (via marshal) from the Profile class.
  17.  
  18.     The big change from the previous Profiler (in terms of raw functionality)
  19.     is that an "add()" method has been provided to combine Stats from
  20.     several distinct profile runs.  Both the constructor and the add()
  21.     method now take arbitrarily many file names as arguments.
  22.  
  23.     All the print methods now take an argument that indicates how many lines
  24.     to print.  If the arg is a floating point number between 0 and 1.0, then
  25.     it is taken as a decimal percentage of the available lines to be printed
  26.     (e.g., .1 means print 10% of all available lines).  If it is an integer,
  27.     it is taken to mean the number of lines of data that you wish to have
  28.     printed.
  29.  
  30.     The sort_stats() method now processes some additional options (i.e., in
  31.     addition to the old -1, 0, 1, or 2).  It takes an arbitrary number of quoted
  32.     strings to select the sort order.  For example sort_stats(\'time\', \'name\')
  33.     sorts on the major key of "internal function time", and on the minor
  34.     key of \'the name of the function\'.  Look at the two tables in sort_stats()
  35.     and get_sort_arg_defs(self) for more examples.
  36.  
  37.     All methods now return "self",  so you can string together commands like:
  38.         Stats(\'foo\', \'goo\').strip_dirs().sort_stats(\'calls\').                            print_stats(5).print_callers(5)
  39.     '''
  40.     
  41.     def __init__(self, *args):
  42.         if not len(args):
  43.             arg = None
  44.         else:
  45.             arg = args[0]
  46.             args = args[1:]
  47.         self.init(arg)
  48.         self.add(*args)
  49.  
  50.     
  51.     def init(self, arg):
  52.         self.all_callees = None
  53.         self.files = []
  54.         self.fcn_list = None
  55.         self.total_tt = 0
  56.         self.total_calls = 0
  57.         self.prim_calls = 0
  58.         self.max_name_len = 0
  59.         self.top_level = { }
  60.         self.stats = { }
  61.         self.sort_arg_dict = { }
  62.         self.load_stats(arg)
  63.         trouble = 1
  64.         
  65.         try:
  66.             self.get_top_level_stats()
  67.             trouble = 0
  68.         finally:
  69.             pass
  70.  
  71.  
  72.     
  73.     def load_stats(self, arg):
  74.         if not arg:
  75.             self.stats = { }
  76.         elif type(arg) == type(''):
  77.             f = open(arg, 'rb')
  78.             self.stats = marshal.load(f)
  79.             f.close()
  80.             
  81.             try:
  82.                 file_stats = os.stat(arg)
  83.                 arg = time.ctime(file_stats.st_mtime) + '    ' + arg
  84.             except:
  85.                 pass
  86.  
  87.             self.files = [
  88.                 arg]
  89.         elif hasattr(arg, 'create_stats'):
  90.             arg.create_stats()
  91.             self.stats = arg.stats
  92.             arg.stats = { }
  93.         
  94.         if not self.stats:
  95.             raise TypeError, "Cannot create or construct a %r object from '%r''" % (self.__class__, arg)
  96.         
  97.  
  98.     
  99.     def get_top_level_stats(self):
  100.         for cc, nc, tt, ct, callers in self.stats.items():
  101.             self.total_calls += nc
  102.             self.prim_calls += cc
  103.             self.total_tt += tt
  104.             if len(func_std_string(func)) > self.max_name_len:
  105.                 self.max_name_len = len(func_std_string(func))
  106.                 continue
  107.             self if callers.has_key(('jprofile', 0, 'profiler')) else self
  108.         
  109.  
  110.     
  111.     def add(self, *arg_list):
  112.         if not arg_list:
  113.             return self
  114.         
  115.         if len(arg_list) > 1:
  116.             self.add(*arg_list[1:])
  117.         
  118.         other = arg_list[0]
  119.         if type(self) != type(other) or self.__class__ != other.__class__:
  120.             other = Stats(other)
  121.         
  122.         self.files += other.files
  123.         self.total_calls += other.total_calls
  124.         self.prim_calls += other.prim_calls
  125.         self.total_tt += other.total_tt
  126.         for func in other.top_level:
  127.             self.top_level[func] = None
  128.         
  129.         self.fcn_list = None
  130.         for func, stat in other.stats.iteritems():
  131.             self.stats[func] = add_func_stats(old_func_stat, stat)
  132.         
  133.         return self
  134.  
  135.     
  136.     def dump_stats(self, filename):
  137.         '''Write the profile data to a file we know how to load back.'''
  138.         f = file(filename, 'wb')
  139.         
  140.         try:
  141.             marshal.dump(self.stats, f)
  142.         finally:
  143.             f.close()
  144.  
  145.  
  146.     sort_arg_dict_default = {
  147.         'calls': (((1, -1),), 'call count'),
  148.         'cumulative': (((3, -1),), 'cumulative time'),
  149.         'file': (((4, 1),), 'file name'),
  150.         'line': (((5, 1),), 'line number'),
  151.         'module': (((4, 1),), 'file name'),
  152.         'name': (((6, 1),), 'function name'),
  153.         'nfl': (((6, 1), (4, 1), (5, 1)), 'name/file/line'),
  154.         'pcalls': (((0, -1),), 'call count'),
  155.         'stdname': (((7, 1),), 'standard name'),
  156.         'time': (((2, -1),), 'internal time') }
  157.     
  158.     def get_sort_arg_defs(self):
  159.         '''Expand all abbreviations that are unique.'''
  160.         if not self.sort_arg_dict:
  161.             self.sort_arg_dict = dict = { }
  162.             bad_list = { }
  163.             for word, tup in self.sort_arg_dict_default.iteritems():
  164.                 fragment = word
  165.                 while fragment:
  166.                     if not fragment:
  167.                         break
  168.                     
  169.                     if fragment in dict:
  170.                         bad_list[fragment] = 0
  171.                         break
  172.                     
  173.                     dict[fragment] = tup
  174.                     fragment = fragment[:-1]
  175.             
  176.             for word in bad_list:
  177.                 del dict[word]
  178.             
  179.         
  180.         return self.sort_arg_dict
  181.  
  182.     
  183.     def sort_stats(self, *field):
  184.         if not field:
  185.             self.fcn_list = 0
  186.             return self
  187.         
  188.         if len(field) == 1 and type(field[0]) == type(1):
  189.             field = [
  190.                 {
  191.                     -1: 'stdname',
  192.                     0: 'calls',
  193.                     1: 'time',
  194.                     2: 'cumulative' }[field[0]]]
  195.         
  196.         sort_arg_defs = self.get_sort_arg_defs()
  197.         sort_tuple = ()
  198.         self.sort_type = ''
  199.         connector = ''
  200.         for word in field:
  201.             sort_tuple = sort_tuple + sort_arg_defs[word][0]
  202.             self.sort_type += connector + sort_arg_defs[word][1]
  203.             connector = ', '
  204.         
  205.         stats_list = []
  206.         for cc, nc, tt, ct, callers in self.stats.iteritems():
  207.             stats_list.append((cc, nc, tt, ct) + func + (func_std_string(func), func))
  208.         
  209.         stats_list.sort(TupleComp(sort_tuple).compare)
  210.         self.fcn_list = fcn_list = []
  211.         for tuple in stats_list:
  212.             fcn_list.append(tuple[-1])
  213.         
  214.         return self
  215.  
  216.     
  217.     def reverse_order(self):
  218.         if self.fcn_list:
  219.             self.fcn_list.reverse()
  220.         
  221.         return self
  222.  
  223.     
  224.     def strip_dirs(self):
  225.         oldstats = self.stats
  226.         self.stats = newstats = { }
  227.         max_name_len = 0
  228.         for cc, nc, tt, ct, callers in oldstats.iteritems():
  229.             newfunc = func_strip_path(func)
  230.             if len(func_std_string(newfunc)) > max_name_len:
  231.                 max_name_len = len(func_std_string(newfunc))
  232.             
  233.             newcallers = { }
  234.             for func2, caller in callers.iteritems():
  235.                 newcallers[func_strip_path(func2)] = caller
  236.             
  237.             if newfunc in newstats:
  238.                 newstats[newfunc] = add_func_stats(newstats[newfunc], (cc, nc, tt, ct, newcallers))
  239.                 continue
  240.             newstats[newfunc] = (cc, nc, tt, ct, newcallers)
  241.         
  242.         old_top = self.top_level
  243.         self.top_level = new_top = { }
  244.         for func in old_top:
  245.             new_top[func_strip_path(func)] = None
  246.         
  247.         self.max_name_len = max_name_len
  248.         self.fcn_list = None
  249.         self.all_callees = None
  250.         return self
  251.  
  252.     
  253.     def calc_callees(self):
  254.         if self.all_callees:
  255.             return None
  256.         
  257.         self.all_callees = all_callees = { }
  258.         for cc, nc, tt, ct, callers in self.stats.iteritems():
  259.             if func not in all_callees:
  260.                 all_callees[func] = { }
  261.             
  262.             for func2, caller in callers.iteritems():
  263.                 if func2 not in all_callees:
  264.                     all_callees[func2] = { }
  265.                 
  266.                 all_callees[func2][func] = caller
  267.             
  268.         
  269.  
  270.     
  271.     def eval_print_amount(self, sel, list, msg):
  272.         new_list = list
  273.         if type(sel) == type(''):
  274.             new_list = []
  275.             for func in list:
  276.                 if re.search(sel, func_std_string(func)):
  277.                     new_list.append(func)
  278.                     continue
  279.             
  280.         else:
  281.             count = len(list)
  282.             if type(sel) == type(1.0):
  283.                 if sel <= sel:
  284.                     pass
  285.                 elif sel < 1.0:
  286.                     count = int(count * sel + 0.5)
  287.                     new_list = list[:count]
  288.                 elif type(sel) == type(1):
  289.                     if sel <= sel:
  290.                         pass
  291.                     elif sel < count:
  292.                         count = sel
  293.                         new_list = list[:count]
  294.                     
  295.         if len(list) != len(new_list):
  296.             msg = msg + '   List reduced from %r to %r due to restriction <%r>\n' % (len(list), len(new_list), sel)
  297.         
  298.         return (new_list, msg)
  299.  
  300.     
  301.     def get_print_list(self, sel_list):
  302.         width = self.max_name_len
  303.         if self.fcn_list:
  304.             list = self.fcn_list[:]
  305.             msg = '   Ordered by: ' + self.sort_type + '\n'
  306.         else:
  307.             list = self.stats.keys()
  308.             msg = '   Random listing order was used\n'
  309.         for selection in sel_list:
  310.             (list, msg) = self.eval_print_amount(selection, list, msg)
  311.         
  312.         count = len(list)
  313.         if not list:
  314.             return (0, list)
  315.         
  316.         print msg
  317.         if count < len(self.stats):
  318.             width = 0
  319.             for func in list:
  320.                 if len(func_std_string(func)) > width:
  321.                     width = len(func_std_string(func))
  322.                     continue
  323.             
  324.         
  325.         return (width + 2, list)
  326.  
  327.     
  328.     def print_stats(self, *amount):
  329.         for filename in self.files:
  330.             print filename
  331.         
  332.         if self.files:
  333.             print 
  334.         
  335.         indent = ' ' * 8
  336.         for func in self.top_level:
  337.             print indent, func_get_function_name(func)
  338.         
  339.         print indent, self.total_calls, 'function calls',
  340.         if self.total_calls != self.prim_calls:
  341.             print '(%d primitive calls)' % self.prim_calls,
  342.         
  343.         print 'in %.3f CPU seconds' % self.total_tt
  344.         print 
  345.         (width, list) = self.get_print_list(amount)
  346.         if list:
  347.             self.print_title()
  348.             for func in list:
  349.                 self.print_line(func)
  350.             
  351.             print 
  352.             print 
  353.         
  354.         return self
  355.  
  356.     
  357.     def print_callees(self, *amount):
  358.         (width, list) = self.get_print_list(amount)
  359.         if list:
  360.             self.calc_callees()
  361.             self.print_call_heading(width, 'called...')
  362.             for func in list:
  363.                 if func in self.all_callees:
  364.                     self.print_call_line(width, func, self.all_callees[func])
  365.                     continue
  366.                 self.print_call_line(width, func, { })
  367.             
  368.             print 
  369.             print 
  370.         
  371.         return self
  372.  
  373.     
  374.     def print_callers(self, *amount):
  375.         (width, list) = self.get_print_list(amount)
  376.         if list:
  377.             self.print_call_heading(width, 'was called by...')
  378.             for func in list:
  379.                 (cc, nc, tt, ct, callers) = self.stats[func]
  380.                 self.print_call_line(width, func, callers)
  381.             
  382.             print 
  383.             print 
  384.         
  385.         return self
  386.  
  387.     
  388.     def print_call_heading(self, name_size, column_title):
  389.         print 'Function '.ljust(name_size) + column_title
  390.  
  391.     
  392.     def print_call_line(self, name_size, source, call_dict):
  393.         print func_std_string(source).ljust(name_size),
  394.         if not call_dict:
  395.             print '--'
  396.             return None
  397.         
  398.         clist = call_dict.keys()
  399.         clist.sort()
  400.         name_size = name_size + 1
  401.         indent = ''
  402.         for func in clist:
  403.             name = func_std_string(func)
  404.             print indent * name_size + name + '(%r)' % (call_dict[func],), f8(self.stats[func][3])
  405.             indent = ' '
  406.         
  407.  
  408.     
  409.     def print_title(self):
  410.         print '   ncalls  tottime  percall  cumtime  percall', 'filename:lineno(function)'
  411.  
  412.     
  413.     def print_line(self, func):
  414.         (cc, nc, tt, ct, callers) = self.stats[func]
  415.         c = str(nc)
  416.         if nc != cc:
  417.             c = c + '/' + str(cc)
  418.         
  419.         print c.rjust(9), f8(tt),
  420.         if nc == 0:
  421.             print ' ' * 8,
  422.         else:
  423.             print f8(tt / nc),
  424.         print f8(ct),
  425.         if cc == 0:
  426.             print ' ' * 8,
  427.         else:
  428.             print f8(ct / cc),
  429.         print func_std_string(func)
  430.  
  431.     
  432.     def ignore(self):
  433.         pass
  434.  
  435.  
  436.  
  437. class TupleComp:
  438.     '''This class provides a generic function for comparing any two tuples.
  439.     Each instance records a list of tuple-indices (from most significant
  440.     to least significant), and sort direction (ascending or decending) for
  441.     each tuple-index.  The compare functions can then be used as the function
  442.     argument to the system sort() function when a list of tuples need to be
  443.     sorted in the instances order.'''
  444.     
  445.     def __init__(self, comp_select_list):
  446.         self.comp_select_list = comp_select_list
  447.  
  448.     
  449.     def compare(self, left, right):
  450.         for index, direction in self.comp_select_list:
  451.             l = left[index]
  452.             r = right[index]
  453.             if l < r:
  454.                 return -direction
  455.             
  456.             if l > r:
  457.                 return direction
  458.                 continue
  459.         
  460.         return 0
  461.  
  462.  
  463.  
  464. def func_strip_path(func_name):
  465.     (filename, line, name) = func_name
  466.     return (os.path.basename(filename), line, name)
  467.  
  468.  
  469. def func_get_function_name(func):
  470.     return func[2]
  471.  
  472.  
  473. def func_std_string(func_name):
  474.     return '%s:%d(%s)' % func_name
  475.  
  476.  
  477. def add_func_stats(target, source):
  478.     '''Add together all the stats for two profile entries.'''
  479.     (cc, nc, tt, ct, callers) = source
  480.     (t_cc, t_nc, t_tt, t_ct, t_callers) = target
  481.     return (cc + t_cc, nc + t_nc, tt + t_tt, ct + t_ct, add_callers(t_callers, callers))
  482.  
  483.  
  484. def add_callers(target, source):
  485.     '''Combine two caller lists in a single list.'''
  486.     new_callers = { }
  487.     for func, caller in target.iteritems():
  488.         new_callers[func] = caller
  489.     
  490.     for func, caller in source.iteritems():
  491.         if func in new_callers:
  492.             new_callers[func] = caller + new_callers[func]
  493.             continue
  494.         new_callers[func] = caller
  495.     
  496.     return new_callers
  497.  
  498.  
  499. def count_calls(callers):
  500.     '''Sum the caller statistics to get total number of calls received.'''
  501.     nc = 0
  502.     for calls in callers.itervalues():
  503.         nc += calls
  504.     
  505.     return nc
  506.  
  507.  
  508. def f8(x):
  509.     return '%8.3f' % x
  510.  
  511. if __name__ == '__main__':
  512.     import cmd
  513.     
  514.     try:
  515.         import readline
  516.     except ImportError:
  517.         pass
  518.  
  519.     
  520.     class ProfileBrowser(cmd.Cmd):
  521.         
  522.         def __init__(self, profile = None):
  523.             cmd.Cmd.__init__(self)
  524.             self.prompt = '% '
  525.             if profile is not None:
  526.                 self.stats = Stats(profile)
  527.             else:
  528.                 self.stats = None
  529.  
  530.         
  531.         def generic(self, fn, line):
  532.             args = line.split()
  533.             processed = []
  534.             for term in args:
  535.                 
  536.                 try:
  537.                     processed.append(int(term))
  538.                 except ValueError:
  539.                     pass
  540.  
  541.                 
  542.                 try:
  543.                     frac = float(term)
  544.                     if frac > 1 or frac < 0:
  545.                         print 'Fraction argument mus be in [0, 1]'
  546.                         continue
  547.                     
  548.                     processed.append(frac)
  549.                 except ValueError:
  550.                     pass
  551.  
  552.                 processed.append(term)
  553.             
  554.             if self.stats:
  555.                 getattr(self.stats, fn)(*processed)
  556.             else:
  557.                 print 'No statistics object is loaded.'
  558.             return 0
  559.  
  560.         
  561.         def generic_help(self):
  562.             print 'Arguments may be:'
  563.             print '* An integer maximum number of entries to print.'
  564.             print '* A decimal fractional number between 0 and 1, controlling'
  565.             print '  what fraction of selected entries to print.'
  566.             print '* A regular expression; only entries with function names'
  567.             print '  that match it are printed.'
  568.  
  569.         
  570.         def do_add(self, line):
  571.             self.stats.add(line)
  572.             return 0
  573.  
  574.         
  575.         def help_add(self):
  576.             print 'Add profile info from given file to current statistics object.'
  577.  
  578.         
  579.         def do_callees(self, line):
  580.             return self.generic('print_callees', line)
  581.  
  582.         
  583.         def help_callees(self):
  584.             print 'Print callees statistics from the current stat object.'
  585.             self.generic_help()
  586.  
  587.         
  588.         def do_callers(self, line):
  589.             return self.generic('print_callers', line)
  590.  
  591.         
  592.         def help_callers(self):
  593.             print 'Print callers statistics from the current stat object.'
  594.             self.generic_help()
  595.  
  596.         
  597.         def do_EOF(self, line):
  598.             print ''
  599.             return 1
  600.  
  601.         
  602.         def help_EOF(self):
  603.             print 'Leave the profile brower.'
  604.  
  605.         
  606.         def do_quit(self, line):
  607.             return 1
  608.  
  609.         
  610.         def help_quit(self):
  611.             print 'Leave the profile brower.'
  612.  
  613.         
  614.         def do_read(self, line):
  615.             if line:
  616.                 
  617.                 try:
  618.                     self.stats = Stats(line)
  619.                 except IOError:
  620.                     args = None
  621.                     print args[1]
  622.                     return None
  623.  
  624.                 self.prompt = line + '% '
  625.             elif len(self.prompt) > 2:
  626.                 line = self.prompt[-2:]
  627.             else:
  628.                 print 'No statistics object is current -- cannot reload.'
  629.             return 0
  630.  
  631.         
  632.         def help_read(self):
  633.             print 'Read in profile data from a specified file.'
  634.  
  635.         
  636.         def do_reverse(self, line):
  637.             self.stats.reverse_order()
  638.             return 0
  639.  
  640.         
  641.         def help_reverse(self):
  642.             print 'Reverse the sort order of the profiling report.'
  643.  
  644.         
  645.         def do_sort(self, line):
  646.             abbrevs = self.stats.get_sort_arg_defs()
  647.             if line and not filter((lambda x, a = abbrevs: x not in a), line.split()):
  648.                 self.stats.sort_stats(*line.split())
  649.             else:
  650.                 print 'Valid sort keys (unique prefixes are accepted):'
  651.                 for key, value in Stats.sort_arg_dict_default.iteritems():
  652.                     print '%s -- %s' % (key, value[1])
  653.                 
  654.             return 0
  655.  
  656.         
  657.         def help_sort(self):
  658.             print 'Sort profile data according to specified keys.'
  659.             print "(Typing `sort' without arguments lists valid keys.)"
  660.  
  661.         
  662.         def complete_sort(self, text, *args):
  663.             return _[1]
  664.  
  665.         
  666.         def do_stats(self, line):
  667.             return self.generic('print_stats', line)
  668.  
  669.         
  670.         def help_stats(self):
  671.             print 'Print statistics from the current stat object.'
  672.             self.generic_help()
  673.  
  674.         
  675.         def do_strip(self, line):
  676.             self.stats.strip_dirs()
  677.             return 0
  678.  
  679.         
  680.         def help_strip(self):
  681.             print 'Strip leading path information from filenames in the report.'
  682.  
  683.         
  684.         def postcmd(self, stop, line):
  685.             if stop:
  686.                 return stop
  687.             
  688.  
  689.  
  690.     import sys
  691.     print 'Welcome to the profile statistics browser.'
  692.     if len(sys.argv) > 1:
  693.         initprofile = sys.argv[1]
  694.     else:
  695.         initprofile = None
  696.     
  697.     try:
  698.         ProfileBrowser(initprofile).cmdloop()
  699.         print 'Goodbye.'
  700.     except KeyboardInterrupt:
  701.         pass
  702.  
  703.  
  704.